package com.db.concurrency.producerconsumer.executors;

import java.io.File;
import java.io.FileFilter;
import java.util.List;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author Alexander Kotov (kotov.alex.22@gmail.com)
 */
public class FileCrawler implements Runnable {
    private final List<BlockingDeque<File>> tasksList;
    private final int id;
    private final BlockingDeque<File> fileQueue;
    private final ExecutorService executorService;
    private final FileFilter fileFilter;
    private final File root;
    private final CountDownLatch doneSignal;
    private final AtomicInteger counter;

    public FileCrawler(List<BlockingDeque<File>> tasksList,
                       int id,
                       ExecutorService executorService,
                       final FileFilter fileFilter,
                       File root,
                       CountDownLatch doneSignal,
                       AtomicInteger counter) {
        this.tasksList = tasksList;
        this.id = id;
        this.fileQueue = tasksList.get(id);
        this.executorService = executorService;
        this.root = root;
        this.fileFilter = new FileFilter() {
            public boolean accept(File f) {
                return f.isDirectory() || fileFilter.accept(f);
            }
        };
        this.doneSignal = doneSignal;
        this.counter = counter;
    }

    public FileCrawler(List<BlockingDeque<File>> tasksList,
                       int id,
                       ExecutorService executorService,
                       final FileFilter fileFilter,
                       File root,
                       CountDownLatch doneSignal) {
        this(tasksList, id, executorService, fileFilter, root, doneSignal, new AtomicInteger(1));
    }

    private boolean alreadyIndexed(File f) {
        return false;
    }

    public void run() {
        try {
            crawl(root);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        finally {
            if (counter.decrementAndGet() == 0) {
                doneSignal.countDown();
            }
        }
    }

    private void crawl(File root) throws InterruptedException {
        File[] entries = root.listFiles(fileFilter);
        if (entries != null) {
            for (File entry : entries) {
                if (entry.isDirectory()) {
                    counter.incrementAndGet();
                    int nextId = (id + 1) % tasksList.size();
                    executorService.submit(new FileCrawler(tasksList, nextId, executorService, fileFilter, entry, doneSignal, counter));
                }
                else if (!alreadyIndexed(entry)) {
                    fileQueue.put(entry);
                }
            }
        }
    }
}

